#include <config.h>
#include <enums.h>
#include <session.h>
#include <QFile>
#include <QMenu>
#include <QMessageBox>
#include <material_editor/shadereditor.h>
#include <material_editor/textureeditor.h>
#include <ldr/loadingsystem.h>
#include <ldr/bin/ilimageloader.h>
#include <ldr/xml/xmldefaultresourcelocator.h>
#include <ldr/xml/xmleffectloader.h>
#include <ldr/xml/xmlmaterialloader.h>
#include <ldr/xml/xmlmeshloader.h>
#include <ldr/xml/xmlprogramloader.h>
#include <ldr/xml/xmlshaderloader.h>
#include <ldr/xml/xmltextureloader.h>
#include <ldr/txt/glslshaderloader.h>

#include <stdio.h>
#include <vfs.h>

Session* Session::static_instance = 0;

Session::Session()
  : QObject(0)
{
}

void Session::Initialize ()
{
  _mainWindow = new MainWindow();
  _sceneView = new SceneView();

	ceLoadingSystem::Get ()->AddLoader (new ceXMLEffectLoader());
  ceLoadingSystem::Get ()->AddLoader (new ceXMLProgramLoader());
  ceLoadingSystem::Get ()->AddLoader (new ceGLSLShaderLoader ());
  ceLoadingSystem::Get ()->AddLoader (new ceILImageLoader());
	ceLoadingSystem::Get ()->AddLoader (new ceXMLMaterialLoader ());
	ceLoadingSystem::Get ()->AddLoader (new ceXMLShaderLoader ());
	ceLoadingSystem::Get ()->AddLoader (new ceXMLTextureLoader ());
	ceLoadingSystem::Get ()->AddLoader (new ceXMLMeshLoader ());
  ceLoadingSystem::Get ()->AddResourceLocator(new ceXMLDefaultResourceLocator ("resources.xml"));

  _engine = new ceEngine ();
  ceEngine::Config config;
  memset (&config, 0, sizeof(config));
  config.window       = _sceneView->GetWindow();
  config.windowCreate = false;
  MakeGLContextCurrent();
  if (!_engine->Initialize(config))
    {
      printf ("Unable to initialize CrimsonCore-Engine\n");
      fflush(stdout);
    }

  _materialManager = new MaterialManager ();
  _objectManager = new ObjectManager();

  _mainWindow->setWindowTitle(CE_TOOL_NAME);


  _materialView = new MaterialView (_materialManager);
  _materialView->ConnectSignals ();
  _materialView->CreateMenu(_mainWindow);

  _objectBrowserView = new ObjectBrowserView (_objectManager);
  _objectBrowserView->ConnectSignals();
  _objectBrowserView->CreateMenu(_mainWindow);

  _objectComposerView = new ObjectComposerView(_objectManager);
  _objectComposerView->ConnectSignals();
  _objectComposerView->CreateMenu(_mainWindow);

  _centerStack = new QStackedWidget();
  _centerStack->addWidget(_materialView);
  _centerStack->addWidget(_objectBrowserView);
  _centerStack->addWidget(_objectComposerView);
  _mainWindow->setCentralWidget(_centerStack);

  connect (_mainWindow->GetAction(MainWindow::Action_MaterialView), SIGNAL(triggered()),
           this, SLOT(ShowMaterialView()));
  connect (_mainWindow->GetAction(MainWindow::Action_ObjectBrowser), SIGNAL(triggered()),
           this, SLOT(ShowObjectBrowser()));
  connect (_mainWindow->GetAction(MainWindow::Action_ObjectComposer), SIGNAL(triggered()),
           this, SLOT(ShowObjectComposer()));

  ChangeStackPage(SP_ObjectBrowser);
//  InitMMData ();

  QFile file (":/style/media/style.qss");
  if (file.open (QFile::ReadOnly))
    {
      QString styleSheet = QLatin1String (file.readAll ());
//      app.setStyleSheet (styleSheet);
    }
}

void Session::ShowMaterialView()
{
  ChangeStackPage(SP_MaterialView);
}

void Session::ShowMaterialView(Material* material)
{
  ChangeStackPage(SP_MaterialView);
  _materialView->EditMaterial(material);
}

void Session::ShowObjectBrowser()
{
  ChangeStackPage(SP_ObjectBrowser);
}

void Session::ShowObjectComposer()
{
  ChangeStackPage(SP_ObjectComposer);
}

void Session::ChangeStackPage (StackPage page)
{
  _centerStack->setCurrentIndex(page);

  _mainWindow->GetAction(MainWindow::Action_MaterialView)->setChecked(page == SP_MaterialView);
  _mainWindow->GetAction(MainWindow::Action_ObjectBrowser)->setChecked(page == SP_ObjectBrowser);
  _mainWindow->GetAction(MainWindow::Action_ObjectComposer)->setChecked(page == SP_ObjectComposer);
}

void Session::Open(const QString &projectFolder)
{
	MakeGLContextCurrent();
  SetProjectFolder(projectFolder);
  _materialManager->Load(MaterialManager::DV_All);
  _materialManager->CreateDefaultMaterial();
  _objectBrowserView->CreateScene();
  _objectManager->Load();
}

void Session::InitMMData ()
{
  Texture* txt = _materialManager->CreateTexture();
  txt->SetName("Texture");
  txt->SetCategory(Category("Textures.my.private.textures"));
  _materialManager->AddTexture(txt);

  Shader* shd = _materialManager->CreateShader();
  shd->SetName("Phong");
  shd->SetShaderType(ST_Vertex);
  shd->SetCategory(Category ("Shaders.Standard"));
  shd->SetCode("\n"
               "#version 130\n"
               "\n"
               "attribute vec4 vertex;\n"
               "attribute vec3 normal;\n"
               "attribute vec2 txt;\n"
               "uniform mat4 matrix_world;\n"
               "uniform mat4 matrix_view;\n"
               "uniform mat4 matrix_projection;\n"
               "varying vec2 tex_coord;\n"
               "\n"
               "void main ()\n"
               "{\n"
               "  gl_Position = matrix_projection * matrix_view * matrix_world * vertex;\n"
               "  tex_coord = txt;\n"
               "}\n"
               );
  _materialManager->AddShader(shd);

  shd = _materialManager->CreateShader();
  shd->SetName("Phong");
  shd->SetShaderType(ST_Fragment);
  shd->SetCategory(Category ("Shaders.Standard"));
  shd->SetCode("#version 130\n"
               "\n"
               "uniform sampler2d texture_diffuse;\n"
               "varying vec2 tex_coord;\n"
               "\n"
               "void main ()\n"
               "{\n"
               "  gl_FragColor = texture2d (texture_diffuse, tex_coord);\n"
               "}\n"
               "\n");
  _materialManager->AddShader(shd);

  Program* prog = _materialManager->CreateProgram();
  prog->SetName("Phong");
  prog->SetCategory(Category ("Programs.Standard"));
  _materialManager->AddProgram(prog);

  Material* mat = _materialManager->CreateMaterial();
  mat->SetName("Grass");
  mat->SetCategory(Category ("Materials.Outsides.Grasses"));
  _materialManager->AddMaterial(mat);

  _materialView->EditMaterial(mat);
}

Session* Session::Get()
{
  if (!Session::static_instance)
    {
      Session::static_instance = new Session ();
    }
  return Session::static_instance;
}

bool Session::MakeGLContextCurrent()
{
  return _sceneView->GetSceneEditor()->MakeGLContextCurrent();
}

void Session::SetProjectFolder(const QString &projectFolder)
{
  _projectFolder = projectFolder;
  ceVFS::Get()->SetRootPath(std::string((const char*)projectFolder.toAscii()));
}

const QString& Session::GetProjectFolder() const
{
  return _projectFolder;
}

MaterialManager* Session::GetMaterialManager()
{
  return _materialManager;
}

MainWindow* Session::GetMainWindow()
{
  return _mainWindow;
}

ceEngine* Session::GetEngine()
{
  return _engine;
}

iDevice* Session::GetDevice()
{
  return _engine->GetDevice();
}

